#include "Scanner.h"

function initScanner(char filename[])
{
    file = fopen (filename, "r");
	if (file equ NULL)
	{
		printf ("Can not open file: %s.\n", filename);
		exit(1);
	}

	log = fopen ("log.txt", "w");
	if(log equ NULL)
	{
	    printf ("Can not open file: log.txt\n");
		exit(1);
	}

    time_t t;
    time(&t);
	fprintf(log, "Init SimpleAllStars - Scanner at Time: %s\n", ctime(&t));

	errCount = 0;

	int no;
	initKeyTab();

	lnCounter = 1;
    colCounter = 1;
    curKey.length = 0;
    nextChar();
}

function get()
{
    curKey.value[0] = current;
    curKey.length = 1;

    forgetSpaces();
    curKey.column = colCounter;
    curKey.line = lnCounter;

    if      (current equ ';')
    {
        curKey.sym = COLON;
        nextChar();
    }
    elif (current equ '"')
    {
        string();
    }
    elif (current equ ')')
    {
        curKey.sym = RPAREN;
        nextChar();
    }
    elif (current equ '}')
    {
        curKey.sym = RBRACE;
        nextChar();
    }
    elif (current equ ']')
    {
        curKey.sym = RBRAK;
        nextChar();
    }
    elif (current equ '*')
    {
        curKey.sym = TIMES;
        nextChar();
    }
    elif (current equ '(')
    {
        curKey.sym = LPAREN;
        nextChar();
    }
    elif (current equ '[')
    {
        curKey.sym = LBRAK;
        nextChar();
    }
    elif (current equ '{')
    {
        curKey.sym = LBRACE;
        nextChar();
    }
    elif (current equ '/')
    {
        nextChar();
        if(current equ '*')
        {
            mark("!!!Comment start!!!", 0);
            skipComment();
        }
        else
        {
            curKey.sym = DIV;
        }
    }
    elif (current equ '%')
    {
        curKey.sym = MOD;
        nextChar();
    }
    elif (current equ '+')
    {
        curKey.sym = PLUS;
        nextChar();
    }
    elif (current equ '-')
    {
        nextChar();
        if(current equ '>')
        {
            curKey.sym = ARROW;
            nextChar();
        }
        else
        {
            curKey.sym = MINUS;
        }
    }
    elif (current equ '=')
    {
        curKey.sym = BECOME;
        nextChar();
    }
    elif (current equ '<')
    {
        nextChar();
        if(current equ '=')
        {
            curKey.sym = LEQ;
            nextChar();
        }
        else
        {
            curKey.sym = LSS;
        }
    }
    elif (current equ '>')
    {
        nextChar();
        if(current equ '=')
        {
            curKey.sym = GEQ;
            nextChar();
        }
        else
        {
            curKey.sym = GRT;
        }
    }
    elif (current equ ',')
    {
        curKey.sym = COMMA;
        nextChar();
    }
    elif (current equ '.')
    {
        curKey.sym = PERIOD;
        nextChar();
    }
    elif(current >= 97 and current <= 122 or //a ... z
            current >= 65 and current <= 90)    //A ... Z
    {
        nextChar();
            //Identifier
        while(current >= 97 and current <= 122 or //a ... z
              current >= 65 and current <= 90  or //A ... Z
              current >= 48 and current <= 57)    //0 ... 9
        {
            nextChar();
        }
        curKey.length = curKey.length - 1;
        curKey.sym = IDENT;
        keyword();
        curKey.length = curKey.length + 1;
    }
    elif(current >= 48 and current <= 57) //0 ... 9
    {
        nextChar();
        while(current >= 48 and current <= 57)
        {
            nextChar();
        }
        curKey.sym = NUMBER;
    }
    elif(current equ '\'')
    {
        nextChar();
        nextChar();
        if(current equ '\'')
        {
            curKey.sym = CHAR;
        }
        else
        {
            curKey.sym = UNKN;
        }
        nextChar();
    }
    elif(read neq EOF)
    {
        curKey.sym = UNKN;
        nextChar();
    }
    curKey.length = curKey.length - 1;

    //printSymInfo();
}

function string()
{
    if (current equ '"')
    {
        nextChar();
        while(current neq '"' and curKey.sym neq ENDF)
        {
            nextChar();
        }
        if(curKey.sym equ ENDF)
        {
            mark("String has no end\n", 1);
            return;
        }
        else
        {
            curKey.sym = STRING;
            nextChar();
        }
    }
}

function printSymInfo()
{
    int i = 0;
    //printf("curkey.length: %d\n", curKey.length);
    printf("\nNext Sym\n");
    printf("********\n");
    while(i < curKey.length)
    {
        printf("Sym: %d    \"%c\"", curKey.sym, curKey.value[i]);
        printf("    Col: %d     Ln: %d\n", colCounter, lnCounter);
        i++;
    }
}
function skipComment()
{
    while(current neq '*' and curKey.sym neq ENDF)
    {
        nextChar();
        curKey.length = 0;
    }
    if(curKey.sym neq ENDF)
    {
        nextChar();
    }

    if(current neq '/' and curKey.sym neq ENDF)
    {
        skipComment();
    }
    else
    {
        nextChar();
        mark("!!!Comment   end!!!", 0);
        get();
    }
}

function forgetSpaces()
{
    while((current equ ' ' or current equ '\n' or current equ '\t' or current equ '\r') and curKey.sym neq ENDF)
    {
        curKey.length = curKey.length - 1;
        nextChar();
    }
}

function keyword()
{
    int j = 0;
    while(j < keyTabLength)
    {
        if(keyTab[j].length equ curKey.length)
        {
            int equality = 0;
            int i = 0;
            while(i < curKey.length)
            {
                if(keyTab[j].value[i] equ curKey.value[i])
                {
                    equality++;
                }
                i++;
            }
            if(equality equ curKey.length)
            {
                curKey.sym = keyTab[j].sym;
            }
        }
        j++;
    }
}

function initKeyTab()
{
    keyTab[0].sym = AND;
    keyTab[0].value[0] = 'a';
    keyTab[0].value[1] = 'n';
    keyTab[0].value[2] = 'd';
    keyTab[0].length = 3;

    keyTab[1].sym = INVOL;
    keyTab[1].value[0] = 'i';
    keyTab[1].value[1] = 'n';
    keyTab[1].value[2] = 'v';
    keyTab[1].value[3] = 'o';
    keyTab[1].value[4] = 'l';
    keyTab[1].value[5] = 'v';
    keyTab[1].value[6] = 'e';
    keyTab[1].length = 7;

    keyTab[2].sym = OR;
    keyTab[2].value[0] = 'o';
    keyTab[2].value[1] = 'r';
    keyTab[2].length = 2;

    keyTab[3].sym = FUNC;
    keyTab[3].value[0] = 'f';
    keyTab[3].value[1] = 'u';
    keyTab[3].value[2] = 'n';
    keyTab[3].value[3] = 'c';
    keyTab[3].value[4] = 't';
    keyTab[3].value[5] = 'i';
    keyTab[3].value[6] = 'o';
    keyTab[3].value[7] = 'n';
    keyTab[3].length = 8;

    keyTab[4].sym = EQL;
    keyTab[4].value[0] = 'e';
    keyTab[4].value[1] = 'q';
    keyTab[4].value[2] = 'u';
    keyTab[4].length = 3;

    keyTab[5].sym = NEQ;
    keyTab[5].value[0] = 'n';
    keyTab[5].value[1] = 'e';
    keyTab[5].value[2] = 'q';
    keyTab[5].length = 3;

    keyTab[6].sym = IF;
    keyTab[6].value[0] = 'i';
    keyTab[6].value[1] = 'f';
    keyTab[6].length = 2;

    keyTab[7].sym = ELIF;
    keyTab[7].value[0] = 'e';
    keyTab[7].value[1] = 'l';
    keyTab[7].value[2] = 'i';
    keyTab[7].value[3] = 'f';
    keyTab[7].length = 4;

    keyTab[8].sym = ELSE;
    keyTab[8].value[0] = 'e';
    keyTab[8].value[1] = 'l';
    keyTab[8].value[2] = 's';
    keyTab[8].value[3] = 'e';
    keyTab[8].length = 4;

    keyTab[9].sym = WHILE;
    keyTab[9].value[0] = 'w';
    keyTab[9].value[1] = 'h';
    keyTab[9].value[2] = 'i';
    keyTab[9].value[3] = 'l';
    keyTab[9].value[4] = 'e';
    keyTab[9].length = 5;

    keyTab[10].sym = SEQ;
    keyTab[10].value[0] = 's';
    keyTab[10].value[1] = 'e';
    keyTab[10].value[2] = 'q';
    keyTab[10].value[3] = 'u';
    keyTab[10].value[4] = 'e';
    keyTab[10].value[5] = 'n';
    keyTab[10].value[6] = 'c';
    keyTab[10].value[7] = 'e';
    keyTab[10].length = 8;

    keyTab[11].sym = STRUCT;
    keyTab[11].value[0] = 's';
    keyTab[11].value[1] = 't';
    keyTab[11].value[2] = 'r';
    keyTab[11].value[3] = 'u';
    keyTab[11].value[4] = 'c';
    keyTab[11].value[5] = 't';
    keyTab[11].length = 6;

    keyTab[12].sym = TYP;
    keyTab[12].value[0] = 'c';
    keyTab[12].value[1] = 'h';
    keyTab[12].value[2] = 'a';
    keyTab[12].value[3] = 'r';
    keyTab[12].length = 4;

    keyTab[13].sym = TYP;
    keyTab[13].value[0] = 'i';
    keyTab[13].value[1] = 'n';
    keyTab[13].value[2] = 't';
    keyTab[13].length = 3;

    keyTab[14].sym = PTR;
    keyTab[14].value[0] = 'p';
    keyTab[14].value[1] = 't';
    keyTab[14].value[2] = 'r';
    keyTab[14].length = 3;

    keyTab[15].sym = CONST;
    keyTab[15].value[0] = 'c';
    keyTab[15].value[1] = 'o';
    keyTab[15].value[2] = 'n';
    keyTab[15].value[3] = 's';
    keyTab[15].value[4] = 't';
    keyTab[15].length = 5;

    keyTab[16].sym = TYP;
    keyTab[16].value[0] = 'b';
    keyTab[16].value[1] = 'o';
    keyTab[16].value[2] = 'o';
    keyTab[16].value[3] = 'l';
    keyTab[16].length = 4;

    keyTab[17].sym = BOOL;
    keyTab[17].value[0] = 't';
    keyTab[17].value[1] = 'r';
    keyTab[17].value[2] = 'u';
    keyTab[17].value[3] = 'e';
    keyTab[17].length = 4;

    keyTab[18].sym = BOOL;
    keyTab[18].value[0] = 'f';
    keyTab[18].value[1] = 'a';
    keyTab[18].value[2] = 'l';
    keyTab[18].value[3] = 's';
    keyTab[18].value[4] = 'e';
    keyTab[18].length = 5;

    keyTabLength = KEYTABLENGTH;
}

function nextChar()
{
	if (read neq EOF)
	{
		read = fscanf (file, "%c", &current);
		checkPos();
		if(curKey.length > 50)
        {
            printf("IdentifierName is to long at Col: %d    and Line: %d\n", colCounter, lnCounter);
            exit(1);
        }
		curKey.value[curKey.length] = current;
		//printf("char read: '%c'   at Pos: %d\n", current, curKey.length);
        curKey.length = curKey.length + 1;
	}
	else
	{
	    curKey.sym = ENDF;
	    //printf("EOF!\n");
        fclose(file);
	}
}

function checkPos()
{
    colCounter = colCounter + 1;
    if(current equ '\n')
    {
        colCounter = 0;
        lnCounter = lnCounter + 1;
    }
}

function mark(char msg[], int err)
{
    if(err equ 1)
    {
        errCount = errCount + 1;
        printf("%d: ERROR: %s at Line: %d   Col: %d\n", errCount, msg, curKey.line, curKey.column);
        fprintf(log,"%d: ERROR: %s at Line: %d   Col: %d\n", errCount, msg, curKey.line, curKey.column);
    }
    else
    {
        printf("INFO: %s at Line: %d   Col: %d\n", msg, curKey.line, curKey.column);
        fprintf(log,"INFO: %s at Line: %d   Col: %d\n", msg, curKey.line, curKey.column);
    }
}

function clearScanner()
{
    fclose(log);
}

char ptr getCurValue()
{
    char ptr structIdent = (char ptr) malloc(curKey.length);
    strncpy(structIdent, curKey.value, curKey.length);
    structIdent[curKey.length] = '\0';

    return structIdent;
}

